﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Fast.Framework.Extensions
{

    /// <summary>
    /// 泛型扩展类
    /// </summary>
    public static class GengricExtensions
    {

        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="source">源</param>
        /// <param name="ignoreKey">忽略主键</param>
        /// <returns></returns>
        public static Dictionary<string, object> GetPropertyValue<T>(this T source, bool ignoreKey = false)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            var type = source.GetType();
            var keyValues = new Dictionary<string, object>();
            var propertyInfos = type.GetProperties().Where(w => !w.IsDefined(typeof(NotMappedAttribute)))
                .Where(w => !w.PropertyType.IsClass || w.PropertyType.Equals(typeof(string)));

            if (ignoreKey)
            {
                propertyInfos = propertyInfos.Where(w => !w.IsDefined(typeof(KeyAttribute)));
            }
            foreach (var propertyInfo in propertyInfos)
            {
                var value = propertyInfo.GetValue(source);
                if (propertyInfo.IsDefined(typeof(ColumnAttribute)))
                {
                    keyValues.Add(propertyInfo.GetCustomAttribute<ColumnAttribute>().Name, value);
                }
                else
                {
                    keyValues.Add(propertyInfo.Name, value);
                }
            }
            return keyValues;
        }

        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="source">源</param>
        /// <param name="ignoreKey">忽略主键</param>
        /// <returns></returns>
        public static List<Dictionary<string, object>> GetPropertyValue<T>(this List<T> source, bool ignoreKey = false)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            var list = new List<Dictionary<string, object>>();
            if (!source.Any())
            {
                return list;
            }
            var type = source.First().GetType();//兼容匿名对象

            var propertyInfos = type.GetProperties().Where(w => !w.IsDefined(typeof(NotMappedAttribute)))
                .Where(w => !w.PropertyType.IsClass || w.PropertyType.Equals(typeof(string)));
            if (ignoreKey)
            {
                propertyInfos = propertyInfos.Where(w => !w.IsDefined(typeof(KeyAttribute)));
            }

            foreach (var item in source)
            {
                var keyValues = new Dictionary<string, object>();
                foreach (var propertyInfo in propertyInfos)
                {
                    var value = propertyInfo.GetValue(item);
                    if (propertyInfo.IsDefined(typeof(ColumnAttribute)))
                    {
                        keyValues.Add(propertyInfo.GetCustomAttribute<ColumnAttribute>().Name, value);
                    }
                    else
                    {
                        keyValues.Add(propertyInfo.Name, value);
                    }
                }
                list.Add(keyValues);
            }
            return list;
        }

        /// <summary>
        /// 到数据表格
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">源</param>
        /// <param name="tableName">表名称</param>
        /// <returns></returns>
        public static DataTable ToDataTable<T>(this IEnumerable<T> source, string tableName = "")
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (!source.Any())
            {
                return null;
            }
            var type = typeof(T);
            DataTable dt = new DataTable(string.IsNullOrWhiteSpace(tableName) ? type.GetTableName() : tableName);

            var propertyInfos = type.GetProperties();

            foreach (var propertyInfo in propertyInfos)
            {
                dt.Columns.Add(propertyInfo.IsDefined(typeof(ColumnAttribute)) ? propertyInfo.GetCustomAttribute<ColumnAttribute>().Name : propertyInfo.Name, propertyInfo.PropertyType);
            }

            foreach (var item in source)
            {
                var dataRow = dt.NewRow();
                for (int i = 0; i < propertyInfos.Length; i++)
                {
                    dataRow.SetField(dt.Columns[i].ColumnName, propertyInfos[i].GetValue(item));
                }
                dt.Rows.Add(dataRow);
            }
            return dt;
        }

    }
}
